﻿using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using PersonalWebsite.Domain.Abstract.Entities.Enum;
using PersonalWebsite.Domain.Abstract.Entities.IAbility;
using PersonalWebsite.Domain.Abstract.Transactions;
using PersonalWebsite.Domain.Abstract.UnitOfWork;
using System.Linq.Expressions;

namespace PersonalWebsite.Domain.Abstract.DBContext
{
    public class DomainDBContext : DbContext, IUnitOfWork, ITransaction
    {
        private readonly IMediator _mediator;

        public DomainDBContext()
        { }

        public DomainDBContext(DbContextOptions options, IMediator mediator) : base(options)
        {
            _mediator = mediator;
        }

        #region 事务

        private IDbContextTransaction _currentTransaction;
        public IDbContextTransaction CurrentTransaction { get { return _currentTransaction; } }
        public bool IsActiveTransaction() => _currentTransaction != null;

        public async Task<IDbContextTransaction> BeginTransaction()
        {
            if (!IsActiveTransaction())
            {
                var result = await this.Database.BeginTransactionAsync();
                _currentTransaction = result;
            }

            return _currentTransaction;
        }

        public async Task CommitTransaction()
        {
            if (IsActiveTransaction())
                await _currentTransaction.CommitAsync();
        }

        public async Task RollbackTransaction()
        {
            if (IsActiveTransaction())
                await _currentTransaction.RollbackAsync();
        }

        #endregion

        #region UnitOfWork

        public async Task<int> SaveChanegeAsync()
        {
            return await SaveChangesAsync();
        }

        #endregion

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                if (typeof(ISoftDelete).IsAssignableFrom(entityType.ClrType))
                {
                    modelBuilder.Entity(entityType.ClrType).Property<IsDeletedEnum>(nameof(ISoftDelete.IsDeleted));
                    var parameter = Expression.Parameter(entityType.ClrType, "e");
                    var callExpression = Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(IsDeletedEnum) }, parameter, Expression.Constant(nameof(ISoftDelete.IsDeleted)));
                    var body = Expression.Equal(callExpression, Expression.Constant(IsDeletedEnum.N));

                    modelBuilder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body, parameter));
                }
            }

            base.OnModelCreating(modelBuilder);
        }
    }
}
